package com.e2u.start;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BootStrap
{
	private static boolean isDebug = false;
	
	private Properties prop = null;
	
	public BootStrap()
	{
		prop = new Properties();
		loadProperties();
	}
	private void loadProperties()
	{
		try
		{
			InputStream is = ClassLoader.getSystemResourceAsStream("BootStrap.properties");			
			prop.load(is);
			is.close();
		}
		catch(Exception e)
		{
			e.printStackTrace(System.out);
		}
	}
	
	private ClassLoader getClassLoader() throws MalformedURLException, IOException
	{
		String cp = prop.getProperty("Class-Path");
		String[] paths = cp.split(File.pathSeparator);
		
		List<File> fileList = new ArrayList<File>();
		
		for(int i = 0; i < paths.length; i++)
		{
			File dir = new File(paths[i]);
			if(!dir.exists())
			{
				printDebug("The dir " + paths[i] + " doesn't exist: " + dir.getCanonicalPath());
				continue;
			}
			//Folder
			if(paths[i].endsWith("/"))
			{
				fileList.add(dir);
				printDebug("The dir " + paths[i] + " is assumed to refer to a directory");
				continue;
			}
			//Get 2 types files: .zip/.jar
			getFilesRecurse(dir, ".+\\.jar$|.+\\.zip$", fileList, true);
		}
		
		URL[] urls = new URL[fileList.size()];
		for(int i = 0, size = fileList.size(); i < size; i++)
		{
			urls[i] = fileList.get(i).toURI().toURL();
			
			printDebug(fileList.get(i).getCanonicalPath());
		}
		
		ClassLoader cl = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
		
		//Set up the new classloader!
		Thread.currentThread().setContextClassLoader(cl);
		
		return cl;
	}
	
	public void boot(String[] args) throws Exception
	{
		ClassLoader cl = getClassLoader();
		
		String mainClassName = prop.getProperty("Main-Class");		
		Class<?> mainClass = cl.loadClass(mainClassName);
		
		Class[] parameterTypes = {String[].class};
		Method mainMethod = mainClass.getMethod("main", parameterTypes);
		
		Object[] parameters = {args};
		mainMethod.invoke(null, parameters);
	}
	
	public static List<File> getFilesRecurse(File dir, final String pattern, List<File> fileList, boolean sortByTime)
	{
		Comparator<File> comparator = new Comparator<File>()
		{
			public int compare(File f1, File f2)
			{
				long result = f2.lastModified() - f1.lastModified();
				if(result == 0)
				{
					return 0;
				}
				return (result > 0) ? 1 : -1;
			}
		};
		return getFilesRecurse(dir, Pattern.compile(pattern), null, true, fileList, comparator);
	}
	public static List<File> getFilesRecurse(File dir, Pattern pattern,
		File exclude, boolean rec, List<File> fileList,
		Comparator<File> comparator)
	{
		File[] files = dir.listFiles();
		if(comparator != null)
		{
			Arrays.sort(files, comparator);
		}
		for(File file : files)
		{
			if(file.equals(exclude))
			{
				continue;
			}
			if(file.isDirectory() && rec)
			{
				getFilesRecurse(file, pattern, exclude, rec, fileList, comparator);
			}
			else
			{
				Matcher m = pattern.matcher(file.getName());
				if(m.matches())
				{
					fileList.add(file);
				}
			}
		}
		return fileList;
	}
	
	private static void printDebug(String str)
	{
		if(isDebug)
		{
			System.out.println(str);
		}
	}
	
	public static void main(String[] args) 
	{
		BootStrap booter = new BootStrap();
		try
		{
			booter.boot(args);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}		
	}
}
